package com.piece.mall.service;

import com.piece.core.framework.support.convert.Convert;
import com.piece.core.framework.util.file.IoUtil;
import com.piece.core.framework.util.string.JsonUtil;
import com.piece.core.framework.util.string.StringUtil;
import com.piece.core.jpa.repository.BaseService;
import com.piece.core.pay.client.PayClientFactory;
import com.piece.core.pay.client.impl.alipay.AliPayClientConfig;
import com.piece.core.pay.client.impl.wxpay.WXPayClientConfig;
import com.piece.file.client.FileClientFactory;
import com.piece.file.model.TbSysFile;
import com.piece.file.service.TbSysFileService;
import com.piece.mall.model.OmsPaymentChannel;
import com.piece.mall.repository.OmsPaymentChannelRepository;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.InputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@Transactional
public class OmsPaymentChannelService extends BaseService<OmsPaymentChannel, String> {

    @Autowired
    private OmsPaymentChannelRepository omsPaymentChannelRepository;

    @Resource
    private TbSysFileService tbSysFileService;

    @Autowired
    private FileClientFactory fileClientFactory;

    @Resource
    private PayClientFactory payClientFactory;

    @PostConstruct
    public void initRepository() {
        setRepository(omsPaymentChannelRepository);

        // 加载所有支付渠道
        List<OmsPaymentChannel> channels = findAll();
        if (CollectionUtils.isNotEmpty(channels)) {
            channels.stream().forEach(channel -> {
                try {
                    initPayClient(channel);
                } catch (Exception e) {
                    log.error("创建支付客户端[{}]异常：{}", channel, e.getMessage());
                }
            });
        }
    }

    private void initPayClient(OmsPaymentChannel channel) throws Exception {
        String channelId = channel.getChannelId();
        Map param = JsonUtil.toMap(channel.getParam());
        switch (channelId) {
            case "1":
                // 支付宝
                AliPayClientConfig aliPayConfig = new AliPayClientConfig();
                aliPayConfig.setAppId(channel.getAppId());
                // 沙盒模式
                aliPayConfig.setServerUrl(AliPayClientConfig.SERVER_URL_SANDBOX);
                aliPayConfig.setSignType(AliPayClientConfig.SIGN_TYPE_DEFAULT);
                aliPayConfig.setNotifyUrl(channel.getPayNotifyUrl());
                aliPayConfig.setReturnUrl(channel.getPayReturnUrl());
                int mode = Convert.toInt(param.get("mode"), 1);
                aliPayConfig.setMode(mode);

                if (1 == mode && StringUtil.isNotEmpty(channel.getPrivateCert())) { // 公钥模式
                    // 商户私钥
                    TbSysFile privateCert = tbSysFileService.findById(channel.getPrivateCert());
                    InputStream is = fileClientFactory.get().downloadFile(privateCert);
                    aliPayConfig.setPrivateKey(IoUtil.readString(is, true));
                    TbSysFile publicCert = tbSysFileService.findById(channel.getPublicCert());
                    is = fileClientFactory.get().downloadFile(publicCert);
                    aliPayConfig.setAlipayPublicKey(IoUtil.readString(is, true));
                } else if (StringUtil.isNotEmpty(channel.getRootCert())) { // 证书模式
                    // 商户公钥应用证书内容
                    TbSysFile privateCert = tbSysFileService.findById(channel.getPrivateCert());
                    InputStream is = fileClientFactory.get().downloadFile(privateCert);
                    aliPayConfig.setAppCertContent(IoUtil.readString(is, true));
                    // 支付宝公钥证书内容
                    TbSysFile publicCert = tbSysFileService.findById(channel.getPublicCert());
                    is = fileClientFactory.get().downloadFile(publicCert);
                    aliPayConfig.setAlipayPublicCertContent(IoUtil.readString(is, true));
                    // 根证书内容
                    TbSysFile rootCert = tbSysFileService.findById(channel.getRootCert());
                    is = fileClientFactory.get().downloadFile(rootCert);
                    aliPayConfig.setRootCertContent(IoUtil.readString(is, true));
                }

                payClientFactory.initPayClient(channelId, channel.getChannelCode(), aliPayConfig);
                break;
            case "2":
                // 微信
                WXPayClientConfig wxPayConfig = new WXPayClientConfig();
                wxPayConfig.setAppId(channel.getAppId());
                wxPayConfig.setMchId(channel.getMchId());
                wxPayConfig.setNotifyUrl(channel.getPayNotifyUrl());
                wxPayConfig.setReturnUrl(channel.getPayReturnUrl());
                wxPayConfig.setRefundUrl(channel.getRefundNotifyUrl());

                // apiclient_key.pem 证书文件
                InputStream is;
                if (StringUtil.isNotEmpty(channel.getPrivateCert())) {
                    TbSysFile wxPayCert = tbSysFileService.findById(channel.getPrivateCert());
                    is = fileClientFactory.get().downloadFile(wxPayCert);
                    wxPayConfig.setPrivateKey(is);
                }
                // apiclient_cert.pem 证书文件
                if (StringUtil.isNotEmpty(channel.getPublicCert())) {
                    TbSysFile wxPayCert = tbSysFileService.findById(channel.getPublicCert());
                    is = fileClientFactory.get().downloadFile(wxPayCert);
                    wxPayConfig.setPrivateCert(is);
                }
                // apiV3 密钥值
                if (StringUtil.isNotEmpty(channel.getRootCert())) {
                    TbSysFile wxPayCert = tbSysFileService.findById(channel.getRootCert());
                    is = fileClientFactory.get().downloadFile(wxPayCert);
                    wxPayConfig.setPrivateCert(is);
                }
                payClientFactory.initPayClient(channelId, channel.getChannelCode(), wxPayConfig);
                break;
            case "3":
                // 银联
                break;
        }
    }

    @Override
    public OmsPaymentChannel insertOrUpdate(OmsPaymentChannel channel) throws Exception {
        boolean updatePrivateCert = true, updatePublicCert = true, updateRootCert = true;
        Long id = channel.getId();

        if (null == id) {
            channel = omsPaymentChannelRepository.insert(channel);
            updatePrivateCert = null != channel.getPrivateCert();
            updatePublicCert = null != channel.getPublicCert();
            updateRootCert = null != channel.getRootCert();
        } else {
            OmsPaymentChannel tempChannel = findById(id);

            if (!StringUtil.equals(tempChannel.getPrivateCert(), channel.getPrivateCert())) {
                if (StringUtil.isNotEmpty(tempChannel.getPrivateCert())) {
                    TbSysFile cert = tbSysFileService.findById(tempChannel.getPrivateCert());
                    fileClientFactory.get().deleteFile(cert);
                }
            } else if (StringUtil.isEmpty(channel.getPrivateCert())) {
                updatePrivateCert = false;
            }
            if (!StringUtil.equals(tempChannel.getPublicCert(), channel.getPublicCert())) {
                if (StringUtil.isNotEmpty(tempChannel.getPublicCert())) {
                    TbSysFile cert = tbSysFileService.findById(tempChannel.getPublicCert());
                    fileClientFactory.get().deleteFile(cert);
                }
            } else if (StringUtil.isEmpty(channel.getPublicCert())) {
                updatePublicCert = false;
            }
            if (!StringUtil.equals(tempChannel.getRootCert(), channel.getRootCert())) {
                if (StringUtil.isNotEmpty(tempChannel.getRootCert())) {
                    TbSysFile cert = tbSysFileService.findById(tempChannel.getRootCert());
                    fileClientFactory.get().deleteFile(cert);
                }
            } else if (StringUtil.isEmpty(channel.getRootCert())) {
                updateRootCert = false;
            }
            omsPaymentChannelRepository.update(channel);
        }

        List<TbSysFile> updateFiles = new ArrayList<>();
        if (updatePrivateCert) {
            TbSysFile privateCert = tbSysFileService.findById(channel.getPrivateCert());
            privateCert.setTable(channel.getClass().getSimpleName());
            privateCert.setBusinessId(channel.getId() + "");
            updateFiles.add(privateCert);
        }

        if (updatePublicCert) {
            TbSysFile publicCert = tbSysFileService.findById(channel.getPublicCert());
            publicCert.setTable(channel.getClass().getSimpleName());
            publicCert.setBusinessId(channel.getId() + "");
            updateFiles.add(publicCert);
        }

        if (updateRootCert) {
            TbSysFile rootCert = tbSysFileService.findById(channel.getRootCert());
            rootCert.setTable(channel.getClass().getSimpleName());
            rootCert.setBusinessId(channel.getId() + "");
            updateFiles.add(rootCert);
        }

        if (updateFiles.size() > 0) {
            tbSysFileService.batchUpdate(updateFiles);
        }

        initPayClient(channel);
        return channel;
    }

    @Override
    public int delete(Serializable[] ids) throws Exception {
        for (Serializable id : ids) {
            // 删除支付客户端
            payClientFactory.removePayClient(Convert.toStr(id));
            OmsPaymentChannel channel = findById(id);
            // 删除证书文件
            TbSysFile cert;
            if (StringUtil.isNotEmpty(channel.getPublicCert())) {
                cert = tbSysFileService.findById(channel.getPublicCert());
                fileClientFactory.get().deleteFile(cert);
            }
            if (StringUtil.isNotEmpty(channel.getPrivateCert())) {
                cert = tbSysFileService.findById(channel.getPrivateCert());
                fileClientFactory.get().deleteFile(cert);
            }
            if (StringUtil.isNotEmpty(channel.getRootCert())) {
                cert = tbSysFileService.findById(channel.getRootCert());
                fileClientFactory.get().deleteFile(cert);
            }
            repository.delete(id);
        }

        return ids.length;
    }
}
